package core.molecules.atoms;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.TreeSet;

import core.molecules.IMolecule;
import core.molecules.MoleculeBase;
import core.molecules.atoms.subatomic.SubatomicParticle;
import core.molecules.atoms.subatomic.traditional.Electron;
import core.molecules.atoms.subatomic.traditional.Neutron;
import core.molecules.atoms.subatomic.traditional.Proton;



import util.XYZPosition;

public abstract class Atom extends MoleculeBase<SubatomicParticle> {


	private XYZPosition myPosition;
	protected TreeSet<SpecialState> myStates;
	protected String myAtomCode;
	
	public enum SpecialState{
		FIVE_PRIME,
		THREE_PRIME,
		METHYLATED,
		TERMINAL; //TODO: is this what T is?		
	}
	
	public Atom( String ac, int id){
		this(0,0,0, ac, id);
	}

	public Atom (double x, double y, double z, String ac, int id){
		this(new XYZPosition(x,y,z), ac, id);
	}
	

	public Atom(XYZPosition pos, String ac, int id) {
		super(id);
		setPosition(pos);
		setBaseParticles();
		setAtomCode(ac);
		myStates = new TreeSet<SpecialState>();
	}

	public String getAtomCode() {
		if (myAtomCode == null) return this.getAbbr();
		return myAtomCode;
	}

	public void setAtomCode(String ac) {
		this.myAtomCode = ac;
	}

	public void addState(SpecialState s){
		myStates.add(s);
	}
	
	public void removeState(SpecialState s){
		myStates.remove(s);
	}
	
	public boolean hasState(SpecialState s){
		return myStates.contains(s);
	}
	
	
	
	private void setBaseParticles() {
		addNeutrons(getBaseNeutronNum());
		addProtons(getBaseProtonsNum());
		addElectrons(getBaseElectronNum());
	}



	protected abstract int getBaseNeutronNum();
	protected abstract int getBaseProtonsNum();
	protected abstract int getBaseElectronNum();




	

	public double addElectrons(int num) {
		return this.addSubMolecules(Electron.class, num);
	}

	public double addProtons(int num) {
		return this.addSubMolecules(Proton.class, num);
	}

	public double addNeutrons(int num) {
		return this.addSubMolecules(Neutron.class, num);
	}



	public double numElectrons() {
		return this.getMoleculesOfType(Electron.class).size();
	}

	public double numProtons() {
		return this.getMoleculesOfType(Proton.class).size();
	}

	public double numNeutrons() {
		return this.getMoleculesOfType(Neutron.class).size();
	}

	public void setPosition(XYZPosition pos) {
		this.myPosition = pos;
	}

	public XYZPosition getPosition() {
		return myPosition;
	}
	
	public int oxidize(int n){
		this.removeElectrons(n);
		return this.getOxidationState();
	}

	public int reduce(int n){
		this.addElectrons(n);
		return this.getOxidationState();
	}

	public double removeElectrons(int n) {
		return this.removeParticles(Electron.class, n);
	}



	public void setID(int myID) {
		this.myID = myID;
	}
	
	@Override
	public String toString() {
		return this.getClass().getSimpleName() + "|ID: " + this.getID() + "|Position: " + this.getPosition() + "\n";
	}

	@Override
	public abstract double getMass();

}
